home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / FTPSERV.C < prev    next >
C/C++ Source or Header  |  1990-05-02  |  21KB  |  844 lines

  1. /* FTP Server state machine - see RFC 959 */
  2.  
  3. #define LINELEN        128    /* Length of command buffer */
  4.  
  5. #include <stdio.h>
  6. #include <ctype.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "netuser.h"
  10. #include "timer.h"
  11. #include "tcp.h"
  12. #include "ftp.h"
  13. #ifdef ATARI_ST
  14. # ifdef __TURBOC__
  15. #  include <tos.h>
  16. # else
  17. #  include <osbind.h>
  18. # endif
  19. #endif
  20.  
  21. /* Command table */
  22. static char *commands[] = {
  23.     "user",
  24. #define USER_CMD    0
  25.     "acct",
  26. #define ACCT_CMD    1
  27.     "pass",
  28. #define PASS_CMD    2
  29.     "type",
  30. #define TYPE_CMD    3
  31.     "list",
  32. #define LIST_CMD    4
  33.     "cwd",
  34. #define CWD_CMD        5
  35.     "dele",
  36. #define DELE_CMD    6
  37.     "name",
  38. #define NAME_CMD    7
  39.     "quit",
  40. #define QUIT_CMD    8
  41.     "retr",
  42. #define RETR_CMD    9
  43.     "stor",
  44. #define STOR_CMD    10
  45.     "port",
  46. #define PORT_CMD    11
  47.     "nlst",
  48. #define NLST_CMD    12
  49.     "pwd",
  50. #define PWD_CMD        13
  51.     "xpwd",            /* For compatibility with 4.2BSD */
  52. #define XPWD_CMD    14
  53.     "mkd ",
  54. #define MKD_CMD        15
  55.     "xmkd",            /* For compatibility with 4.2BSD */
  56. #define XMKD_CMD    16
  57.     "xrmd",            /* For compatibility with 4.2BSD */
  58. #define XRMD_CMD    17
  59.     "rmd ",
  60. #define RMD_CMD        18
  61.     "stru",
  62. #define STRU_CMD    19
  63.     "mode",
  64. #define MODE_CMD    20
  65. #if (defined(ATARI_ST))
  66.     "xatr",            /* own extension: set attribs */
  67. #define XATR_CMD    21
  68. #endif
  69.     NULLCHAR
  70. };
  71.  
  72. /* Response messages */
  73. static char sending[]    = "150 Opening data connection for %s \"%s\"\r\n";
  74. #if (defined(ATARI_ST))
  75. static char xatrok[]    = "200 \"%s\" XATR ok\r\n";
  76. #endif
  77. static char okay[]    = "200 Ok\r\n";
  78. static char portok[]    = "200 Port command okay\r\n";
  79. static char typeok[]    = "200 Type OK\r\n";
  80. static char banner[]    = "220 %s FTP version %s ready at %.24s\r\n";
  81. static char bye[]    = "221 Goodbye!\r\n";
  82. static char rxok[]    = "226 File received OK\r\n";
  83. static char txok[]    = "226 File sent OK\r\n";
  84. static char logged[]    = "230 Logged in\r\n";
  85. static char deleok[]    = "250 File deleted\r\n";
  86. static char mkdok[]    = "257 \"%s\" directory created\r\n";
  87. static char pwdmsg[]    = "257 \"%s\" is current directory\r\n";
  88. static char givepass[]    = "331 Enter PASS command\r\n";
  89. static char noconn[]    = "425 Data connection reset\r\n";
  90. static char badcmd[]    = "500 Unknown command\r\n";
  91. static char unsupp[]    = "500 Unsupported command or option\r\n";
  92. static char badport[]    = "501 Bad port syntax\r\n";
  93. #if (defined(ATARI_ST))
  94. static char badxatr[]    = "501 Bad XATR syntax\r\n";
  95. #endif
  96. static char only8[]    = "501 Only logical bytesize 8 supported\r\n";
  97. static char badtype[]    = "501 Unknown type \"%s\"\r\n";
  98. static char unimp[]    = "502 Command not yet implemented\r\n";
  99. static char notlog[]    = "530 Please log in with USER and PASS\r\n";
  100. #if (defined(ATARI_ST))
  101. static char xatrfail[]    = "550 \"%s\" XATR failed\r\n";
  102. #endif
  103. static char cantopen[]    = "550 Can't read file \"%s\"\r\n";
  104. static char delefail[]    = "550 Delete failed\r\n";
  105. static char noperm[]    = "550 Permission denied\r\n";
  106. static char cantmake[]    = "553 Can't create \"%s\"\r\n";
  107. static char nodir[]    = "553 Can't read directory \"%s\"\r\n";
  108.  
  109. static struct tcb *ftp_tcb;
  110.  
  111. /* Start up FTP service */
  112. ftp1(argc,argv)
  113. int argc;
  114. char *argv[];
  115. {
  116.     struct socket lsocket;
  117.     void ftpscr(),ftpscs();
  118.     char tos = 0;
  119.  
  120.     lsocket.address = ip_addr;
  121.     if(argc < 2)
  122.         lsocket.port = FTP_PORT;
  123.     else {
  124.         if((lsocket.port = atoi(argv[1])) == 0)
  125.             lsocket.port = FTP_PORT;
  126.         tos = get_tos(argv[2]);
  127.     }
  128.  
  129.     ftp_tcb = open_tcp(&lsocket,NULLSOCK,TCP_SERVER,0,ftpscr,NULLVFP,ftpscs,tos,(char *)NULL);
  130.     return 0;
  131. }
  132. ftp0()
  133. {
  134.     if(ftp_tcb != NULLTCB)
  135.         close_tcp(ftp_tcb);
  136.     return 0;
  137. }
  138. /* FTP Server Control channel State change upcall handler */
  139. static
  140. void
  141. ftpscs(tcb,old,new)
  142. struct tcb *tcb;
  143. char old,new;
  144. {
  145.     extern char hostname[],version[];
  146.     struct ftp *ftp,*ftp_create();
  147.     void ftp_delete();
  148.     long t;
  149.  
  150.     switch(new){
  151. /* Setting QUICKSTART piggybacks the server's banner on the SYN/ACK segment;
  152.  * leaving it unset waits for the three-way handshake to complete before
  153.  * sending the banner. Piggybacking unfortunately breaks some old TCPs,
  154.  * so its use is not (yet) recommended.
  155. */
  156. #ifdef    QUICKSTART
  157.     case SYN_RECEIVED:
  158. #else
  159.     case ESTABLISHED:
  160. #endif
  161.         if((ftp = ftp_create(LINELEN)) == NULLFTP){
  162.             /* No space, kill connection */
  163.             close_tcp(tcb);
  164.             return;
  165.         }
  166.         ftp->control = tcb;        /* Downward link */
  167.         tcb->user = (char *)ftp;    /* Upward link */
  168.  
  169.         /* Set default data port */
  170.         ftp->port.address = tcb->conn.remote.address;
  171.         ftp->port.port = FTPD_PORT;
  172.  
  173.         log_tcp(tcb,"open FTP");
  174.         time(&t);
  175.         tprintf(ftp->control,banner,hostname,version,ctime(&t));
  176.         break;
  177.     case CLOSE_WAIT:
  178.         close_tcp(tcb);
  179.         break;
  180.     case CLOSED:
  181.         if(tcb != ftp_tcb)
  182.             log_tcp(tcb,"close FTP");
  183.         if((ftp = (struct ftp *)tcb->user) != NULLFTP)
  184.             ftp_delete(ftp);
  185.         /* Check if server is being shut down */
  186.         if(tcb == ftp_tcb)
  187.             ftp_tcb = NULLTCB;
  188.         del_tcp(tcb);
  189.         break;
  190.     }
  191. }
  192.  
  193. /* FTP Server Control channel Receiver upcall handler */
  194. static
  195. void
  196. ftpscr(tcb,cnt)
  197. struct tcb *tcb;
  198. int16 cnt;
  199. {
  200.     register struct ftp *ftp;
  201.     char c;
  202.     struct mbuf *bp;
  203.     void ftpcommand();
  204.  
  205.     if((ftp = (struct ftp *)tcb->user) == NULLFTP){
  206.         /* Unknown connection, just kill it */
  207.         close_tcp(tcb);
  208.         return;
  209.     }
  210.     for (;;){
  211.         switch(ftp->state){
  212.         case COMMAND_STATE:
  213.         /* Assemble an input line in the session buffer. Return if incomplete */
  214.         while(recv_tcp(tcb,&bp,1) == 1){
  215.             pullup(&bp,&c,1);
  216.             switch(c){
  217.             case '\r':    /* Strip cr's */
  218.                 continue;
  219.             case '\n':    /* Complete line; process it */
  220.                 ftp->buf[ftp->cnt] = '\0';
  221.                 ftpcommand(ftp);
  222.                 ftp->cnt = 0;
  223.                 goto again;
  224.             default:    /* Assemble line */
  225.                 if(ftp->cnt != LINELEN-1)
  226.                     ftp->buf[ftp->cnt++] = c;
  227.                 break;
  228.             }
  229.         }
  230.         /* else no linefeed present yet to terminate command */
  231.         return;
  232.         case SENDING_STATE:
  233.         case RECEIVING_STATE:
  234.         /* Leave commands pending on receive queue until
  235.          * present command is done
  236.          */
  237.         return;
  238.         }
  239. again:;
  240.     }
  241. }
  242.  
  243. /* FTP server data channel connection state change upcall handler */
  244. void
  245. ftpsds(tcb,old,new)
  246. struct tcb *tcb;
  247. char old,new;
  248. {
  249.     register struct ftp *ftp;
  250.  
  251.     if((ftp = (struct ftp *)tcb->user) == NULLFTP ||
  252.         !tcpval(ftp->control)){    /* control session existing? */
  253.         /* Unknown connection. Kill it */
  254.         del_tcp(tcb);
  255.         return;
  256.     }
  257.     if(new == CLOSED){
  258.         /* Clear only if another transfer hasn't already started */
  259.         if(ftp->data == tcb)
  260.             ftp->data = NULLTCB;
  261.         del_tcp(tcb);
  262.         if(tcb->reason != NORMAL){
  263.             /* Data connection was reset, complain about it */
  264.             tprintf(ftp->control,noconn);
  265.             /* And clean up */
  266.             if(ftp->fp != NULLFILE && ftp->fp != stdout)
  267.                 fclose(ftp->fp);
  268.             ftp->fp = NULLFILE;
  269.             ftp->state = COMMAND_STATE;
  270.             /* Kick command parser if something is waiting */
  271.             if(ftp->control->rcvcnt != 0)
  272.                 ftpscr(ftp->control,ftp->control->rcvcnt);
  273.             return;
  274.         }
  275.     }
  276.     if(ftp->state == SENDING_STATE && (old == FINWAIT1 || old == CLOSING)){
  277.         /* We've received an ack of our FIN while sending; we're done */
  278.         ftp->state = COMMAND_STATE;
  279.         tprintf(ftp->control,txok);
  280.         /* Kick command parser if something is waiting */
  281.         if(ftp->control->rcvcnt != 0)
  282.             ftpscr(ftp->control,ftp->control->rcvcnt);
  283.         return;
  284.     }
  285.     if(ftp->state == RECEIVING_STATE && new == CLOSE_WAIT){
  286.         /* FIN received on incoming file */
  287. #ifdef    CPM
  288.         if(ftp->type == ASCII_TYPE)
  289.             putc(CTLZ,ftp->fp);
  290. #endif
  291.         close_tcp(tcb);
  292.         if(ftp->fp != stdout)
  293.             fclose(ftp->fp);
  294.         ftp->fp = NULLFILE;
  295.         ftp->state = COMMAND_STATE;
  296.         tprintf(ftp->control,rxok);
  297.         /* Kick command parser if something is waiting */
  298.         if(ftp->control->rcvcnt != 0)
  299.             ftpscr(ftp->control,ftp->control->rcvcnt);
  300.         return;
  301.     }
  302. }
  303.  
  304. /* Parse and execute ftp commands */
  305. static
  306. void
  307. ftpcommand(ftp)
  308. register struct ftp *ftp;
  309. {
  310.     void ftpdr(),ftpdt(),ftpsds();
  311.     char *cmd,*arg,*cp,**cmdp,*file;
  312.     char *pathname();
  313.     char *mode;
  314.     struct socket dport;
  315.     int i;
  316.  
  317. #ifndef CPM
  318.     FILE *dir();
  319. #endif
  320.  
  321.     cmd = ftp->buf;
  322.     if(ftp->cnt == 0){
  323.         /* Can't be a legal FTP command */
  324.         tprintf(ftp->control,badcmd);
  325.         return;
  326.     }
  327.  
  328. #ifdef    UNIX
  329.     /* Translate first word to lower case